package com.teatrace.dao.impl;

import java.io.Serializable;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.hibernate.criterion.DetachedCriteria;
import org.hibernate.criterion.Restrictions;

import com.teatrace.commons.util.DaoHelper;
import com.teatrace.commons.util.HibernateUtils;
import com.teatrace.dao.BaseDao;

public class BaseDaoImpl implements BaseDao {

	private Session session;

    public BaseDaoImpl() {
		session = HibernateUtils.getCurrentSession();
	}

	public <T> void batchDelete(Collection<T> batchObj) throws Exception {
		for (T obj : batchObj) {

			session.delete(obj);
		}
	}

	public <T> void batchSave(Collection<T> batchObj) throws Exception {
		for (T obj : batchObj) {
			session.save(obj);
		}
	}

	public <T> void batchUpdate(Collection<T> batchObj) throws Exception {
		for (T obj : batchObj) {
			session.update(obj);
		}
	}

	public void close() {
		session.close();
	}

	public <T> Long countByCriteria(DetachedCriteria dc) throws Exception {
		throw new UnsupportedOperationException(
				"So far, this method have unimplemented!");
	}

	@SuppressWarnings("unchecked")
	public DetachedCriteria createDetachedCriteria(Class clazz) {
		return DetachedCriteria.forClass(clazz);
	}

	public <T> void delete(T obj) throws Exception {
		session.delete(obj);
	}

	@SuppressWarnings("unchecked")
	public <T> T get(Class<T> clazz, Serializable pk) throws Exception {
		return (T) session.get(clazz, pk);
	}

	public Transaction getTransaction() {
		return session.getTransaction();
	}

	@SuppressWarnings("unchecked")
	public <T> List<T> list(Class<T> clazz) throws Exception {
		String entityName = session.getSessionFactory().getClassMetadata(clazz)
				.getEntityName();
		return session.createQuery("from " + entityName).list();
	}

	@SuppressWarnings("unchecked")
	public <T> List<T> listByCriteria(DetachedCriteria dc) throws Exception {
		return dc.getExecutableCriteria(session).list();
	}

	@SuppressWarnings("unchecked")
	public <T> List<T> listByCriteria(DetachedCriteria dc, int firstResult,
			int maxResult) throws Exception {
		return dc.getExecutableCriteria(session).setFirstResult(firstResult)
				.setMaxResults(maxResult).list();
	}

	@SuppressWarnings("unchecked")
	public <T> List<T> listByHQL(String hql) throws Exception {
		return session.createQuery(hql).list();
	}

	@SuppressWarnings("unchecked")
	public <T> List<T> listByNamedQuery(String name, Map<String, Object> params)
			throws Exception {
		Query query = session.getNamedQuery(name);
		for (Entry<String, Object> entry : params.entrySet()) {
			query.setParameter(entry.getKey(), entry.getValue());
		}
		return query.list();
	}

	@SuppressWarnings("unchecked")
	public <T> T load(Class<T> clazz, Serializable pk) throws Exception {
		return (T) session.load(clazz, pk);
	}

	public <T> void save(T obj) throws Exception {
		session.save(obj);
	}

	public <T> void saveOrUpdate(T obj) throws Exception {
		session.saveOrUpdate(obj);
	}

	public <T> void update(T obj) throws Exception {
		session.update(obj);
	}

	public <T> void batchPersist(Collection<T> batchObj) throws Exception {
		for (T obj : batchObj) {
			session.persist(obj);
		}
	}

	public Session getSession() {
		return session;
	}

	public <T> void persist(T obj) throws Exception {
		session.persist(obj);
	}

	public <T> List<T> listByPage(Class<T> clazz, int firstResult,
			int maxResults) throws Exception {
		return session.createQuery("from " + clazz.getName()).setFirstResult(
				firstResult).setMaxResults(maxResults).list();
	}

	public <T> List<T> listByProperty(Class<T> clazz, T obj, String propertyName)
			throws Exception {
		DetachedCriteria dc = this.createDetachedCriteria(clazz).add(
				Restrictions.eq(propertyName, DaoHelper.getValue(clazz, obj,
						propertyName)));
		return this.listByCriteria(dc);
	}

	public Long count(Class clazz) throws Exception {
		Query query = session.createQuery("select count(*) from "
				+ clazz.getSimpleName());
		return Long.parseLong(query.uniqueResult().toString());
	}

}
